package com.ruoyi.framework.weChat.connect;

import cn.hutool.core.map.MapUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.social.oauth2.OAuth2Parameters;
import org.springframework.social.oauth2.OAuth2Template;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.Map;

/**
 * @Classname WeChatOauth2Template
 * @Description TODO
 * @Author h21448-hxtq
 * @Date 2020-04-01 15 : 17
 * @Version 1.0
 */
@Slf4j
public class WeChatOauth2Template extends OAuth2Template {
    private String clientId;

    private String clientSecret;

    private String accessTokenUrl;

    private static final String REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token";

    public WeChatOauth2Template(String clientId, String clientSecret, String authorizeUrl, String accessTokenUrl) {

        super(clientId, clientSecret, authorizeUrl, accessTokenUrl);
        setUseParametersForClientAuthentication(true);
        this.clientId = clientId;
        this.clientSecret = clientSecret;
        this.accessTokenUrl = accessTokenUrl;
    }
    // 通过appId与appSecret去换取access-token
    @Override
    public AccessGrant exchangeForAccess (String authorizationCode, String redirectUri,
                                          MultiValueMap<String, String> parameters) {
        log.info(redirectUri);
        StringBuilder accessTokenRequestUrl=new StringBuilder(accessTokenUrl);

        accessTokenRequestUrl.append("?appid="+clientId);
        accessTokenRequestUrl.append("&secret="+clientSecret);
        accessTokenRequestUrl.append("&code="+authorizationCode);
        accessTokenRequestUrl.append("&grant_type=authorization_code");
        accessTokenRequestUrl.append("&redirect_uri="+redirectUri);

        return getAccessToken(accessTokenRequestUrl);
    }

    // 刷新token
    @Override
    public AccessGrant refreshAccess(String refreshToken, MultiValueMap<String, String> additionalParameters) {
        StringBuilder refreshTokenUrl=new StringBuilder(REFRESH_TOKEN_URL);
        refreshTokenUrl.append("?appid="+clientId);
        refreshTokenUrl.append("&grant_type=refresh_token");
        refreshTokenUrl.append("&refresh_token="+refreshToken);

        return getAccessToken(refreshTokenUrl);
    }

    @SuppressWarnings("unchecked")
    private AccessGrant getAccessToken(StringBuilder accessTokenRequestUrl) {
        log.info("获取access_token的url为："+accessTokenRequestUrl.toString());
        Map<String,Object> result= null;
        try {
            String response = getRestTemplate().getForObject(accessTokenRequestUrl.toString(),String.class);
            log.info("获取的access_token 内容为："+response);
            result=new ObjectMapper().readValue(response,Map.class);
        } catch (Exception e) {
            throw new CustomException(e.getMessage()+",获取access_token失败");
        }

        //返回错误码时直接返回空
        if (StringUtils.isNotBlank(MapUtils.getString(result,"errcode"))) {
            String errcode = MapUtils.getString(result, "errcode");
            String errmsg = MapUtils.getString(result, "errmsg");
            throw new RuntimeException("获取access token失败, errcode:"+errcode+", errmsg:"+errmsg);
        }

        WeChatAccessGrant accessGrant=new WeChatAccessGrant(
                MapUtils.getString(result, "access_token"),
                MapUtils.getString(result, "scope"),
                MapUtils.getString(result, "refresh_token"),
                MapUtils.getLong(result, "expires_in"));
        accessGrant.setOpenId(MapUtils.getString(result,"openid"));

        return accessGrant;
    }

    /**
     * 构建获取授权码的请求。也就是引导用户跳转到微信的地址。
     */
    @Override
    public String buildAuthenticateUrl(OAuth2Parameters parameters) {
        String url=super.buildAuthenticateUrl(parameters);
        url = url+"&appid="+clientId+"&scope=snsapi_login";
        return url;
    }

    @Override
    public String buildAuthorizeUrl(OAuth2Parameters parameters) {
        return buildAuthenticateUrl(parameters);
    }

    /**
     * 微信返回的contentType是html/text，添加相应的HttpMessageConverter来处理。
     */
    @Override
    protected RestTemplate createRestTemplate() {
        RestTemplate restTemplate = super.createRestTemplate();
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
        return restTemplate;
    }

}
